package jwt

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"internal_training_be/config"
	"time"
)

// 生成token
func generateToken(id string, tokenType string) (string, error) {
	// 参数检测
	if id == "" {
		logger.Errorf("id is empty")
		return "", fmt.Errorf("id is empty")
	}
	if tokenType == "" {
		logger.Errorf("tokenType is empty")
		return "", fmt.Errorf("tokenType is empty")
	}

	var audience string
	if tokenType == tokenTypeEmployee {
		audience = employeeAudience
	} else if tokenType == tokenTypeAdmin {
		audience = adminAudience
	} else {
		logger.Errorf("invalid tokenType: %v", tokenType)
		return "", fmt.Errorf("invalid tokenType: %v", tokenType)
	}

	// 创建一个新的Token
	token := jwt.New(jwt.SigningMethodHS256)

	// 创建一个map用于存储claims
	claims := token.Claims.(jwt.MapClaims)

	// 设置JWT的claims
	claims["iss"] = defaultIssuer                                         // 签发者
	claims["sub"] = defaultSubject                                        // 主题
	claims["aud"] = audience                                              // 受众
	claims["iat"] = time.Now().Unix()                                     // 签发时间
	claims["exp"] = time.Now().Add(time.Hour * defaultExpireHours).Unix() // 过期时间
	claims["id"] = id                                                     // 员工ID

	// 从配置文件读取secret
	configReader, err := config.GetConfigReader()
	if err != nil {
		logger.Errorf("failed to get config reader: %v", err)
		return "", fmt.Errorf("failed to get config reader: %v", err)
	}
	secret := configReader.GetString("jwt.secret")

	// 签名并获取完整的编码后的字符串token
	tokenString, err := token.SignedString([]byte(secret))
	if err != nil {
		logger.Errorf("failed to sign token: %v", err)
		return "", fmt.Errorf("failed to sign token: %v", err)
	}

	// 检查token是否为空
	if tokenString == "" {
		logger.Errorf("token is empty")
		return "", fmt.Errorf("token is empty")
	}

	return tokenString, nil
}

// 解析 token
func parseToken(tokenString string) (*jwt.Token, error) {
	// 检查logger是否为空
	if logger == nil {
		fmt.Println("logger is nil")
		return nil, fmt.Errorf("logger is nil")
	}
	// 检查tokenString是否为空
	if tokenString == "" {
		logger.Errorf("tokenString is empty")
		return nil, fmt.Errorf("tokenString is empty")
	}

	// 从配置文件读取secret
	configReader, err := config.GetConfigReader()
	if err != nil {
		logger.Errorf("failed to get config reader: %v", err)
		return nil, fmt.Errorf("failed to get config reader: %v", err)
	}
	secret := configReader.GetString("jwt.secret")

	// 解析token
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// 检查签名方法是否正确
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			logger.Errorf("unexpected signing method: %v", token.Header["alg"])
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}

		// 返回secret
		return []byte(secret), nil
	})
	if err != nil {
		logger.Errorf("failed to parse token: %v", err.Error())

		// 若token已过期，则返回"token is expired"
		if err.Error() == "Token is expired" {
			return nil, fmt.Errorf("token is expired")
		}

		return nil, fmt.Errorf("failed to parse token: %v", err.Error())
	}

	// 检查token是否为空
	if token == nil {
		logger.Errorf("token is empty")
		return nil, fmt.Errorf("token is empty")
	}
	// 检查token是否有效
	if !token.Valid {
		logger.Errorf("token is invalid")
		return nil, fmt.Errorf("token is invalid")
	}

	return token, nil
}

// 验证token
func verifyToken(token *jwt.Token, tokenType string) (bool, error) {
	// 检查logger是否为空
	if logger == nil {
		fmt.Println("logger is nil")
		return false, fmt.Errorf("logger is nil")
	}
	// 检查token是否为空
	if token == nil {
		logger.Errorf("token is empty")
		return false, fmt.Errorf("token is empty")
	}
	// 检查tokenType是否为空
	if tokenType == "" {
		logger.Errorf("tokenType is empty")
		return false, fmt.Errorf("tokenType is empty")
	}
	// 检查token是否有效
	if !token.Valid {
		logger.Errorf("token is invalid")
		return false, fmt.Errorf("token is invalid")
	}

	// 提取claims
	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		logger.Errorf("failed to extract claims")
		return false, fmt.Errorf("failed to extract claims")
	}
	// 检查claims是否为空
	if claims == nil {
		logger.Errorf("claims is empty")
		return false, fmt.Errorf("claims is empty")
	}

	// 检查token是否过期
	if !claims.VerifyExpiresAt(time.Now().Unix(), true) {
		logger.Errorf("token is expired")
		return false, fmt.Errorf("token is expired")
	}

	// 检查签发者是否正确
	if !claims.VerifyIssuer(defaultIssuer, true) {
		logger.Errorf("invalid issuer")
		return false, fmt.Errorf("invalid issuer")
	}

	var targetAudience string
	if tokenType == tokenTypeEmployee {
		targetAudience = employeeAudience
	} else if tokenType == tokenTypeAdmin {
		targetAudience = adminAudience
	} else {
		logger.Errorf("invalid tokenType: %v", tokenType)
		return false, fmt.Errorf("invalid tokenType: %v", tokenType)
	}

	// 检查受众
	if !claims.VerifyAudience(targetAudience, true) {
		logger.Errorf("invalid audience")
		return false, fmt.Errorf("invalid audience")
	}

	return true, nil
}

// getIdFromJwt 从token中获取id
func getIdFromJwt(token *jwt.Token) (string, error) {
	// 检查logger是否为空
	if logger == nil {
		fmt.Println("logger is nil")
		return "", fmt.Errorf("logger is nil")
	}
	// 检查token是否为空
	if token == nil {
		logger.Errorf("token is empty")
		return "", fmt.Errorf("token is empty")
	}
	// 检查token是否有效
	if !token.Valid {
		logger.Errorf("token is invalid")
		return "", fmt.Errorf("token is invalid")
	}

	// 提取claims
	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		logger.Errorf("failed to extract claims")
		return "", fmt.Errorf("failed to extract claims")
	}
	// 检查claims是否为空
	if claims == nil {
		logger.Errorf("claims is empty")
		return "", fmt.Errorf("claims is empty")
	}

	// 从claims中获取id
	id, ok := claims["id"].(string)
	if !ok {
		logger.Errorf("failed to get id")
		return "", fmt.Errorf("failed to get id")
	}
	// 检查userId是否为空
	if id == "" {
		logger.Errorf("id is empty")
		return "", fmt.Errorf("id is empty")
	}

	return id, nil
}
